﻿using ExplorerGame.Gameboard;
using System;
using System.Drawing;
using System.Windows.Forms;

namespace ExplorerGame
{
    public partial class MainForm : Form
    {
        private const int CONSTANT_ELEMENT_SIZE = 100;
        private const int CONSTANT_CAMERA_MOVEMENT = 10;
        private const int CONSTANT_CAMERA_MOVEMENT_ZONE = 25;

        private int previousTickCount;
        private int previousCameraTickCount;
        private Point currentPosition;
        private Point currentMouseLocation;
        private Point currentMouseClickLocation;

        private Gameboard.Gameboard gameboard;

        private readonly Graphics.GameboardGraphics gameboardGraphics;

        public MainForm()
        {
            this.InitializeComponent();

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.Opaque, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            this.gameboardGraphics = new Graphics.GameboardGraphics();
        }

        protected override void OnLoad(EventArgs e)
        {
 	        base.OnLoad(e);

            this.previousTickCount = Environment.TickCount;
            this.previousCameraTickCount = Environment.TickCount;
            
            this.gameboard = new Gameboard.GameboardGenerator().Generate(10, 10);
            this.currentPosition = new Point(0, 0);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            this.currentMouseLocation = e.Location;
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);

            this.currentMouseClickLocation = e.Location;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            // FPS shizzle

            int tickCount = Environment.TickCount;
            int diff = tickCount - this.previousTickCount;
            this.previousTickCount = tickCount;
            int fps;

            if (diff == 0)
            {
                fps = 999;
            }
            else
            {
                fps = 1000 / diff;
            }

            this.Text = string.Format("Explorer running at {0} fps", fps);

            // Process input
            CameraMovingDirection cameraMovingDirection = CameraMovingDirection.None;
            if (this.currentPosition.X + CONSTANT_CAMERA_MOVEMENT < this.gameboard.Width * CONSTANT_ELEMENT_SIZE - e.ClipRectangle.Width && this.currentMouseLocation.X > e.ClipRectangle.Width - CONSTANT_CAMERA_MOVEMENT_ZONE)
            {
                cameraMovingDirection = cameraMovingDirection.Add(CameraMovingDirection.Right);
            }
            if (this.currentPosition.X - CONSTANT_CAMERA_MOVEMENT >= 0 && this.currentMouseLocation.X < CONSTANT_CAMERA_MOVEMENT_ZONE)
            {
                cameraMovingDirection = cameraMovingDirection.Add(CameraMovingDirection.Left);
            }
            if (this.currentPosition.Y + CONSTANT_CAMERA_MOVEMENT < this.gameboard.Height * CONSTANT_ELEMENT_SIZE - e.ClipRectangle.Height && this.currentMouseLocation.Y > e.ClipRectangle.Height - CONSTANT_CAMERA_MOVEMENT_ZONE)
            {
                cameraMovingDirection = cameraMovingDirection.Add(CameraMovingDirection.Down);
            }
            if (this.currentPosition.Y - CONSTANT_CAMERA_MOVEMENT >= 0 && this.currentMouseLocation.Y < CONSTANT_CAMERA_MOVEMENT_ZONE)
            {
                cameraMovingDirection = cameraMovingDirection.Add(CameraMovingDirection.Up);
            }

            // Only change camera position once per second
            if (tickCount - this.previousCameraTickCount > 100)
            {
                if (cameraMovingDirection.Has(CameraMovingDirection.Right))
                {
                    this.currentPosition.X += CONSTANT_CAMERA_MOVEMENT;
                }
                else if (cameraMovingDirection.Has(CameraMovingDirection.Left))
                {
                    this.currentPosition.X -= CONSTANT_CAMERA_MOVEMENT;
                }

                if (cameraMovingDirection.Has(CameraMovingDirection.Down))
                {
                    this.currentPosition.Y += CONSTANT_CAMERA_MOVEMENT;
                }
                else if (cameraMovingDirection.Has(CameraMovingDirection.Up))
                {
                    this.currentPosition.Y -= CONSTANT_CAMERA_MOVEMENT;
                }

                this.previousCameraTickCount = tickCount;
            }

            // Draw gameboard

            e.Graphics.Clear(Color.AliceBlue);

            int widthOffset = 0;
            int heightOffset = 0;

            int currentWidthOffset = this.currentPosition.X % CONSTANT_ELEMENT_SIZE;
            int currentHeightOffset = this.currentPosition.Y % CONSTANT_ELEMENT_SIZE;

            for (int width = this.currentPosition.X / CONSTANT_ELEMENT_SIZE; width < this.gameboard.Width; width++)
            {
                for (int height = this.currentPosition.Y / CONSTANT_ELEMENT_SIZE; height < this.gameboard.Height; height++)
                {
                    Location location = new Location { Width = width, Height = height };

                    if (this.currentMouseClickLocation != Point.Empty)
                    {
                        int viewableLocationX = this.currentMouseClickLocation.X / CONSTANT_ELEMENT_SIZE;
                        int viewableLocationY = this.currentMouseClickLocation.Y / CONSTANT_ELEMENT_SIZE;

                        int nonviewableLocationX = this.currentPosition.X / CONSTANT_ELEMENT_SIZE;
                        int nonviewableLocationY = this.currentPosition.Y / CONSTANT_ELEMENT_SIZE;

                        if (location.Equals(viewableLocationX + nonviewableLocationX, viewableLocationY + nonviewableLocationY))
                        {
                            gameboard.HeroLocation = location;
                            this.currentMouseClickLocation = Point.Empty;

                        }
                    }

                    var gameboardElement = this.gameboard.GetElementAt(width, height);

                    int currentWidth = CONSTANT_ELEMENT_SIZE;
                    int currentHeight = CONSTANT_ELEMENT_SIZE;

                    if (this.currentPosition.X / CONSTANT_ELEMENT_SIZE == width)
                    {
                        currentWidth = CONSTANT_ELEMENT_SIZE - currentWidthOffset;
                    }
                    if (this.currentPosition.Y / CONSTANT_ELEMENT_SIZE == height)
                    {
                        currentHeight = CONSTANT_ELEMENT_SIZE - currentHeightOffset;
                    }

                    gameboardGraphics.DrawGameboardElement(e.Graphics, gameboardElement, widthOffset, heightOffset, currentWidth, currentHeight, gameboard.HeroLocation.Equals(width, height));

                    if (heightOffset == 0 && currentHeightOffset != 0)
                    {
                        heightOffset += CONSTANT_ELEMENT_SIZE - currentHeightOffset;
                    }
                    else
                    {
                        heightOffset += CONSTANT_ELEMENT_SIZE;
                    }

                    if (e.ClipRectangle.Height < heightOffset)
                    {
                        break;
                    }
                }

                if (widthOffset == 0 && currentWidthOffset != 0)
                {
                    widthOffset += CONSTANT_ELEMENT_SIZE - currentWidthOffset;
                }
                else
                {
                    widthOffset += CONSTANT_ELEMENT_SIZE;
                }
                
                heightOffset = 0;

                if (e.ClipRectangle.Width < widthOffset)
                {
                    break;
                }
            }

            if (cameraMovingDirection.Has(CameraMovingDirection.Right))
            {
                e.Graphics.FillRectangle(Brushes.Gold, new Rectangle(e.ClipRectangle.Width - CONSTANT_CAMERA_MOVEMENT_ZONE, 0, CONSTANT_CAMERA_MOVEMENT_ZONE, e.ClipRectangle.Height));
            }
            else if (cameraMovingDirection.Has(CameraMovingDirection.Left))
            {
                e.Graphics.FillRectangle(Brushes.Gold, new Rectangle(0, 0, CONSTANT_CAMERA_MOVEMENT_ZONE, e.ClipRectangle.Height));
            }

            if (cameraMovingDirection.Has(CameraMovingDirection.Down))
            {
                e.Graphics.FillRectangle(Brushes.Gold, new Rectangle(0, e.ClipRectangle.Height - CONSTANT_CAMERA_MOVEMENT_ZONE, e.ClipRectangle.Width, CONSTANT_CAMERA_MOVEMENT_ZONE));
            }
            else if (cameraMovingDirection.Has(CameraMovingDirection.Up))
            {
                e.Graphics.FillRectangle(Brushes.Gold, new Rectangle(0, 0, e.ClipRectangle.Width, CONSTANT_CAMERA_MOVEMENT_ZONE));
            }

            // Restart drawing cycle

            this.Invalidate();
        }
    }
}
